Ontgrendel snellere webprestaties. Leer CSS Grid layoutberekeningen te profileren, de impact van track sizing te analyseren en uw rendering pipeline te optimaliseren met Chrome DevTools.
CSS Grid Track Sizing Performance Profiling: Een Diepgaande Analyse van Layoutberekeningen
CSS Grid heeft een revolutie teweeggebracht in web lay-out, met ongekende kracht en flexibiliteit voor het creĆ«ren van complexe, responsieve ontwerpen. Met functies zoals de `fr`-eenheid, `minmax()`, en content-bewuste dimensionering, kunnen we interfaces bouwen die ooit slechts dromen waren, vaak met verrassend weinig code. Maar met grote kracht komt grote verantwoordelijkheidāen in de wereld van webprestaties ligt die verantwoordelijkheid in het begrijpen van de computationele kosten van onze ontwerpkeuzes.
Hoewel we ons vaak richten op het optimaliseren van JavaScript-uitvoering of het laden van afbeeldingen, is een significant en vaak over het hoofd gezien prestatieknelpunt de layoutberekeningsfase van de browser. Elke keer dat een browser de grootte en positie van elementen op een pagina moet bepalen, voert het een 'Layout'-operatie uit. Complexe CSS, met name met geavanceerde grid-structuren, kan dit proces computationeel duur maken, wat leidt tot trage interacties, vertraagde rendering en een slechte gebruikerservaring. Dit is waar performance profiling niet alleen een tool voor debugging wordt, maar een cruciaal onderdeel van het ontwerp- en ontwikkelingsproces.
Deze uitgebreide gids neemt u mee op een diepgaande verkenning van de wereld van CSS Grid-prestaties. We gaan verder dan de syntaxis en onderzoeken het 'waarom' achter prestatieverschillen. U leert hoe u browser-ontwikkelaarstools kunt gebruiken om layout-knelpunten, veroorzaakt door uw grid track sizing-strategieƫn, te meten, analyseren en diagnosticeren. Aan het eind zult u in staat zijn om lay-outs te bouwen die niet alleen mooi en responsief zijn, maar ook bliksemsnel.
De Rendering Pipeline van de Browser Begrijpen
Voordat we kunnen optimaliseren, moeten we eerst het proces begrijpen dat we proberen te verbeteren. Wanneer een browser een webpagina rendert, volgt het een reeks stappen die vaak de Critical Rendering Path wordt genoemd. Hoewel de exacte terminologie enigszins kan verschillen tussen browsers, zijn de kernfasen over het algemeen consistent:
- Style: De browser parseert de CSS en bepaalt de uiteindelijke stijlen voor elk DOM-element. Dit omvat het oplossen van selectors, het afhandelen van de cascade en het berekenen van de berekende stijl voor elke node.
- Layout (of Reflow): Dit is onze primaire focus. Nadat de stijlen zijn berekend, berekent de browser de geometrie van elk element. Het bepaalt precies waar elk element op de pagina moet komen en hoeveel ruimte het inneemt. Het creƫert een 'layout tree' of 'render tree' die geometrische informatie bevat zoals breedtes, hoogtes en posities.
- Paint: In deze fase vult de browser de pixels in. Het neemt de layout tree uit de vorige stap en zet deze om in een set pixels op het scherm. Dit omvat het tekenen van tekst, kleuren, afbeeldingen, randen en schaduwenāin wezen alle visuele onderdelen van de elementen.
- Composite: De browser tekent de verschillende geschilderde lagen in de juiste volgorde op het scherm. Elementen die overlappen of specifieke eigenschappen hebben zoals `transform` of `opacity` worden vaak in hun eigen lagen behandeld om volgende updates te optimaliseren.
Waarom de 'Layout'-fase Cruciaal is voor Grid-prestaties
De Layout-fase voor een eenvoudig block-and-inline document is relatief eenvoudig. De browser kan elementen vaak in ƩƩn enkele doorgang verwerken, waarbij hun afmetingen worden berekend op basis van hun ouders. CSS Grid introduceert echter een nieuw niveau van complexiteit. Een grid-container is een op beperkingen gebaseerd systeem. De uiteindelijke grootte van een grid track of item hangt vaak af van de grootte van andere tracks, de beschikbare ruimte in de container, of zelfs de intrinsieke grootte van de content binnen de sibling-items.
De layout-engine van de browser moet dit complexe systeem van vergelijkingen oplossen om tot een definitieve lay-out te komen. De manier waarop u uw grid-tracks definieertāuw keuze van dimensioneringseenheden en functiesābeĆÆnvloedt direct de moeilijkheidsgraad en dus de tijd die nodig is om dit systeem op te lossen. Dit is waarom een schijnbaar kleine wijziging in `grid-template-columns` een onevenredige impact kan hebben op de renderingprestaties.
De Anatomie van CSS Grid Track Sizing: Een Prestatieperspectief
Om effectief te profileren, moet u de prestatiekenmerken van de tools die tot uw beschikking staan begrijpen. Laten we de gebruikelijke mechanismen voor track sizing uiteenzetten en hun mogelijke computationele kosten analyseren.
1. Statische en Voorspelbare Dimensionering
Dit zijn de eenvoudigste en meest performante opties omdat ze de layout-engine duidelijke, ondubbelzinnige informatie geven.
- Vaste Eenheden (`px`, `rem`, `em`): Wanneer u een track definieert als `grid-template-columns: 200px 10rem;`, weet de browser onmiddellijk de exacte grootte van deze tracks. Er is geen complexe berekening nodig. Dit is computationeel zeer goedkoop.
- Percentage Eenheden (`%`): Een percentage wordt opgelost ten opzichte van de grootte van de grid-container. Hoewel het ƩƩn extra stap vereist (de breedte van de ouder ophalen), is het nog steeds een zeer snelle en deterministische berekening. De browser kan deze groottes vroeg in het layoutproces oplossen.
Prestatieprofiel: Lay-outs die alleen statische en percentage-dimensionering gebruiken, zijn doorgaans zeer snel. De browser kan de grid-geometrie in ƩƩn enkele, efficiƫnte doorgang oplossen.
2. Flexibele Dimensionering
Deze categorie introduceert flexibiliteit, waardoor tracks zich kunnen aanpassen aan de beschikbare ruimte. Het is iets complexer dan statische dimensionering, maar nog steeds zeer geoptimaliseerd in moderne browsers.
- Fractionele Eenheden (`fr`): De `fr`-eenheid vertegenwoordigt een fractie van de beschikbare ruimte in de grid-container. Om `fr`-eenheden op te lossen, trekt de browser eerst de ruimte af die wordt ingenomen door alle niet-flexibele tracks (zoals `px` of `auto` tracks) en verdeelt vervolgens de resterende ruimte over de `fr`-tracks volgens hun fractie.
Prestatieprofiel: De berekening voor `fr`-eenheden is een proces met meerdere stappen, maar het is een goed gedefinieerde wiskundige operatie die niet afhankelijk is van de inhoud van de grid-items. Voor de meeste gangbare gebruiksscenario's is het extreem performant.
3. Op Inhoud Gebaseerde Dimensionering (De Prestatie-Hotspot)
Hier wordt het interessantāen potentieel traag. Op inhoud gebaseerde dimensioneringssleutelwoorden instrueren de browser om een track te dimensioneren op basis van de inhoud van de items erin. Dit creĆ«ert een krachtige koppeling tussen inhoud en lay-out, maar dit gaat ten koste van computationele kosten.
- `min-content`: Vertegenwoordigt de intrinsieke minimumbreedte van de inhoud. Voor tekst is dit doorgaans de breedte van het langste woord of onbreekbare tekenreeks. Om dit te berekenen, moet de layout-engine van de browser de inhoud conceptueel opmaken om dat breedste deel te vinden.
- `max-content`: Vertegenwoordigt de intrinsieke voorkeursbreedte van de inhoud, wat de breedte is die het zou innemen zonder andere regeleindes dan die expliciet zijn gespecificeerd. Om dit te berekenen, moet de browser de volledige inhoud conceptueel op een enkele, oneindig lange regel opmaken.
- `auto`: Dit sleutelwoord is contextafhankelijk. Wanneer het wordt gebruikt om grid-tracks te dimensioneren, gedraagt het zich over het algemeen als `max-content`, tenzij het item wordt uitgerekt of een gespecificeerde grootte heeft. De complexiteit is vergelijkbaar met `max-content` omdat de browser vaak de inhoud moet meten om de grootte te bepalen.
Prestatieprofiel: Deze sleutelwoorden zijn het meest computationeel duur. Waarom? Omdat ze een tweerichtingsafhankelijkheid creƫren. De lay-out van de container hangt af van de grootte van de inhoud van de items, maar de lay-out van de inhoud van de items kan ook afhangen van de grootte van de container. Om dit op te lossen, moet de browser mogelijk meerdere layout-passes uitvoeren. Het moet eerst de inhoud van elk afzonderlijk item in die track meten voordat het zelfs maar kan beginnen met het berekenen van de uiteindelijke grootte van de track zelf. Voor een grid met veel items kan dit een aanzienlijk knelpunt worden.
4. Op Functies Gebaseerde Dimensionering
Functies bieden een manier om verschillende dimensioneringsmodellen te combineren, wat zowel flexibiliteit als controle biedt.
- `minmax(min, max)`: Deze functie definieert een groottebereik. De prestaties van `minmax()` hangen volledig af van de eenheden die voor de argumenten worden gebruikt. `minmax(200px, 1fr)` is zeer performant, omdat het een vaste waarde combineert met een flexibele. Echter, `minmax(min-content, 500px)` erft de prestatiekosten van `min-content` omdat de browser het nog steeds moet berekenen om te zien of het groter is dan de maximale waarde.
- `fit-content(value)`: Dit is in feite een klem. Het is equivalent aan `minmax(auto, max-content)`, maar geklemd op de gegeven `value`. Dus, `fit-content(300px)` gedraagt zich als `minmax(min-content, max(min-content, 300px))`. Het draagt ook de prestatiekosten van op inhoud gebaseerde dimensionering.
Gereedschap van het Vak: Profiling met Chrome DevTools
Theorie is nuttig, maar data is definitief. Om te begrijpen hoe uw grid-lay-outs in de echte wereld presteren, moet u ze meten. Het Performance-paneel in de DevTools van Google Chrome is hiervoor een onmisbaar hulpmiddel.
Hoe een Prestatieprofiel op te nemen
Volg deze stappen om de gegevens vast te leggen die u nodig heeft:
- Open uw webpagina in Chrome.
- Open DevTools (F12, Ctrl+Shift+I, of Cmd+Opt+I).
- Navigeer naar het tabblad Performance.
- Zorg ervoor dat het selectievakje "Web Vitals" is aangevinkt om nuttige markeringen op uw tijdlijn te krijgen.
- Klik op de Record-knop (de cirkel) of druk op Ctrl+E.
- Voer de actie uit die u wilt profileren. Dit kan de initiƫle paginalading zijn, het vergroten of verkleinen van het browservenster, of een actie die dynamisch inhoud aan het grid toevoegt (zoals het toepassen van een filter). Dit zijn allemaal acties die layoutberekeningen activeren.
- Klik op Stop of druk opnieuw op Ctrl+E.
- DevTools zal de gegevens verwerken en u een gedetailleerde tijdlijn presenteren.
De Flame Chart Analyseren
De flame chart is de belangrijkste visuele weergave van uw opname. Voor lay-outanalyse wilt u zich concentreren op de sectie "Main" thread.
Zoek naar de lange, paarse balken met het label "Rendering". Hierbinnen vindt u donkerdere paarse gebeurtenissen met het label "Layout". Dit zijn de specifieke momenten waarop de browser de geometrie van de pagina berekent.
- Lange Layout-taken: Een enkel, lang 'Layout'-blok is een rode vlag. Beweeg erover om de duur te zien. Elke layout-taak die meer dan een paar milliseconden duurt (bijv. > 10-15ms) op een krachtige machine verdient onderzoek, omdat deze veel langzamer zal zijn op minder krachtige apparaten.
- Layout Thrashing: Zoek naar veel kleine 'Layout'-gebeurtenissen die snel na elkaar plaatsvinden, vaak afgewisseld met JavaScript ('Scripting'-gebeurtenissen). Dit patroon, bekend als layout thrashing, treedt op wanneer JavaScript herhaaldelijk een geometrische eigenschap leest (zoals `offsetHeight`) en vervolgens een stijl schrijft die deze ongeldig maakt, waardoor de browser gedwongen wordt de lay-out steeds opnieuw te berekenen in een lus.
Gebruik van de Samenvatting en de Performance Monitor
- Summary Tab: Na het selecteren van een tijdsbereik in de flame chart, geeft het Summary-tabblad onderaan u een cirkeldiagram met een uitsplitsing van de bestede tijd. Let goed op het percentage dat wordt toegeschreven aan "Rendering" en specifiek "Layout".
- Performance Monitor: Voor real-time analyse opent u de Performance Monitor (vanuit het DevTools-menu: More tools > Performance monitor). Dit biedt live grafieken voor CPU-gebruik, JS heap-grootte, DOM Nodes, en cruciaal, Layouts/sec. Door met uw pagina te interageren en deze grafiek te zien pieken, kunt u direct zien welke acties kostbare layout-herberekeningen veroorzaken.
Praktische Profiling-scenario's: Van Theorie naar Praktijk
Laten we onze kennis testen met enkele praktische voorbeelden. We vergelijken verschillende grid-implementaties en analyseren hun hypothetische prestatieprofielen.
Scenario 1: Vast & Flexibel (`px` en `fr`) vs. Op Inhoud Gebaseerd (`auto`)
Stel je een productgrid voor met 100 items. Laten we twee benaderingen voor de kolommen vergelijken.
Benadering A (Performant): Gebruik `minmax()` met een vast minimum en een flexibel maximum.
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
Benadering B (Potentieel Traag): Gebruik `auto` of `max-content` om de inhoud de kolomgrootte te laten bepalen.
grid-template-columns: repeat(auto-fill, minmax(auto, 300px));
Analyse:
- In Benadering A is de taak van de browser eenvoudig. Hij weet dat de minimumbreedte van elk item 250px is. Hij kan snel berekenen hoeveel items in de breedte van de container passen en vervolgens de resterende ruimte onder hen verdelen. Dit is een snelle, extrinsieke dimensioneringsbenadering waarbij de container de controle heeft. De Layout-taak in het prestatieprofiel zal zeer kort zijn.
- In Benadering B heeft de browser een veel moeilijkere taak. Het `auto`-sleutelwoord (in deze context vaak resulterend in `max-content`) betekent dat om de breedte van een enkele kolom te bepalen, de browser eerst de inhoud van elke van de 100 productkaarten hypothetisch moet renderen om de `max-content`-breedte te vinden. Vervolgens gebruikt het deze meting in zijn grid-oplossingsalgoritme. Deze intrinsieke dimensioneringsbenadering vereist een enorme hoeveelheid meetwerk vooraf voordat de uiteindelijke lay-out kan worden bepaald. De Layout-taak in het prestatieprofiel zal aanzienlijk langer zijn, mogelijk met een factor tien.
Scenario 2: De Kosten van Diep Geneste Grids
Prestatieproblemen met grid kunnen zich opstapelen. Overweeg een lay-out waarbij een ouder-grid op inhoud gebaseerde dimensionering gebruikt, en de kinderen ook complexe grids zijn.
Voorbeeld:
Een hoofdpagina-lay-out is een grid met twee kolommen: `grid-template-columns: max-content 1fr;`. De eerste kolom is een zijbalk met verschillende widgets. Een van deze widgets is een kalender, die zelf is gebouwd met CSS Grid.
Analyse:
De layout-engine van de browser staat voor een uitdagende afhankelijkheidsketen:
- Om de `max-content`-kolom van de hoofdpagina op te lossen, moet het de `max-content`-breedte van de zijbalk berekenen.
- Om de breedte van de zijbalk te berekenen, moet het de breedte van al zijn kinderen berekenen, inclusief de kalenderwidget.
- Om de breedte van de kalenderwidget te berekenen, moet het zijn eigen interne grid-lay-out oplossen.
De berekening voor de ouder wordt geblokkeerd totdat de lay-out van het kind volledig is opgelost. Deze diepe koppeling kan leiden tot verrassend lange lay-outtijden. Als het kind-grid ook op inhoud gebaseerde dimensionering gebruikt, wordt het probleem nog erger. Het profileren van zo'n pagina zou waarschijnlijk een enkele, zeer lange 'Layout'-taak onthullen tijdens de initiƫle render.
Optimalisatiestrategieƫn en Best Practices
Op basis van onze analyse kunnen we verschillende bruikbare strategieƫn afleiden voor het bouwen van high-performance grid-lay-outs.
1. Geef de Voorkeur aan Extrinsieke Dimensionering boven Intrinsieke Dimensionering
Dit is de gouden regel van grid-prestaties. Laat waar mogelijk de grid-container de afmetingen van zijn tracks definiƫren met eenheden als `px`, `rem`, `%` en `fr`. Dit geeft de layout-engine van de browser een duidelijke, voorspelbare set van beperkingen om mee te werken, wat resulteert in snellere berekeningen.
In plaats van dit (Intrinsiek):
grid-template-columns: repeat(auto-fit, max-content);
Geef de voorkeur aan dit (Extrinsiek):
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
2. Beperk de Reikwijdte van Op Inhoud Gebaseerde Dimensionering
Er zijn geldige gebruiksscenario's voor `min-content` en `max-content`, zoals voor dropdown-menu's of labels naast formuliervelden. Wanneer u ze moet gebruiken, probeer dan hun impact te beperken:
- Toepassen op weinig tracks: Gebruik ze op een enkele kolom of rij, niet op een herhalend patroon met honderden items.
- Beperk de ouder: Plaats het grid dat op inhoud gebaseerde dimensionering gebruikt in een container met een `max-width`. Dit geeft de layout-engine een grens, wat soms kan helpen de berekening te optimaliseren.
- Combineer met `minmax()`: Geef een verstandige minimum- of maximumwaarde naast het op inhoud gebaseerde sleutelwoord, zoals `minmax(200px, max-content)`. Dit kan de browser een voorsprong geven bij zijn berekeningen.
3. Begrijp en Gebruik `subgrid` Verstandig
`subgrid` is een krachtige functie waarmee een genest grid de trackdefinitie van zijn ouder-grid kan overnemen. Dit is fantastisch voor uitlijning.
Prestatie-implicaties: `subgrid` kan een tweesnijdend zwaard zijn. Aan de ene kant verhoogt het de koppeling tussen de ouder- en kind-layoutberekeningen, wat theoretisch de initiƫle, complexe layout-oplossing zou kunnen vertragen. Aan de andere kant, door ervoor te zorgen dat items vanaf het begin perfect zijn uitgelijnd, kan het latere layoutverschuivingen en reflows voorkomen die kunnen optreden als u de uitlijning handmatig met andere methoden probeert na te bootsen. Het beste advies is om te profileren. Als u een complexe geneste lay-out heeft, meet dan de prestaties met en zonder `subgrid` om te zien wat beter is voor uw specifieke use case.
4. Virtualisatie: De Ultieme Oplossing voor Grote Datasets
Als u een grid bouwt met honderden of duizenden items (bijv. een datagrid, een oneindig scrollende fotogalerij), zal geen enkele hoeveelheid CSS-aanpassingen het fundamentele probleem overwinnen: de browser moet nog steeds de lay-out voor elk afzonderlijk element berekenen.
De oplossing is virtualisatie (of 'windowing'). Dit is een op JavaScript gebaseerde techniek waarbij u alleen de handvol DOM-elementen rendert die momenteel zichtbaar zijn in de viewport. Terwijl de gebruiker scrollt, hergebruikt u deze DOM-nodes en vervangt u hun inhoud. Dit houdt het aantal elementen dat de browser tijdens een layoutberekening moet verwerken klein en constant, ongeacht of uw dataset 100 of 100.000 items bevat.
Bibliotheken zoals `react-window` en `tanstack-virtual` bieden robuuste implementaties van dit patroon. Voor echt grootschalige grids is dit de meest effectieve prestatie-optimalisatie die u kunt maken.
Casestudy: Optimaliseren van een Productlijstgrid
Laten we een realistische optimalisatiescenario voor een wereldwijde e-commerce website doorlopen.
Het Probleem: De productlijstpagina voelt traag aan. Wanneer het browservenster wordt vergroot of verkleind of filters worden toegepast, is er een merkbare vertraging voordat de producten naar hun nieuwe posities vloeien. De Core Web Vitals-score voor Interaction to Next Paint (INP) is slecht.
De Initiƫle Code (De "Voor"-staat):
Het grid is gedefinieerd om zeer flexibel te zijn, waardoor de productkaarten de kolombreedtes kunnen dicteren op basis van hun inhoud (bijv. lange productnamen).
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, fit-content(320px));
gap: 1rem;
}
De Prestatieanalyse:
- We nemen een prestatieprofiel op terwijl we het browservenster vergroten of verkleinen.
- De flame chart toont een lange, terugkerende 'Layout'-taak elke keer dat het resize-event wordt geactiveerd, die meer dan 80ms duurt op een gemiddeld apparaat.
- De `fit-content()`-functie is afhankelijk van `min-content`- en `max-content`-berekeningen. De profiler bevestigt dat bij elke resize de browser verwoed de inhoud van alle zichtbare productkaarten opnieuw meet om de gridstructuur te herberekenen. Dit is de bron van de vertraging.
De Oplossing (De "Na"-staat):
We schakelen over van een intrinsiek, op inhoud gebaseerd dimensioneringsmodel naar een extrinsiek, door de container gedefinieerd model. We stellen een vaste minimumgrootte in voor de kaarten en laten ze flexibel groeien tot een fractie van de beschikbare ruimte.
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}
Binnen de CSS van de productkaart voegen we regels toe om potentieel lange inhoud sierlijk af te handelen binnen deze nieuwe, meer rigide container:
.product-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
Het Resultaat:
- We nemen een nieuw prestatieprofiel op tijdens het resizen.
- De flame chart toont nu dat de 'Layout'-taak ongelooflijk kort is, consequent onder de 5ms.
- De browser hoeft niet langer de inhoud te meten. Het voert een eenvoudige wiskundige berekening uit op basis van de breedte van de container en het `280px` minimum.
- De gebruikerservaring is getransformeerd. Het vergroten of verkleinen is soepel en onmiddellijk. Het toepassen van filters voelt vlot aan omdat de browser de nieuwe lay-out bijna onmiddellijk kan berekenen.
Een Opmerking over Cross-Browser Tooling
Hoewel deze gids zich heeft gericht op Chrome DevTools, is het cruciaal om te onthouden dat gebruikers uiteenlopende browservoorkeuren hebben. Firefox's Developer Tools hebben een uitstekend Performance-paneel (vaak de 'Profiler' genoemd) dat vergelijkbare flame charts en analysemogelijkheden biedt. Safari's Web Inspector bevat ook een krachtig 'Timelines'-tabblad voor het profileren van renderingprestaties. Test uw optimalisaties altijd in de belangrijkste browsers om een consistente, hoogwaardige ervaring voor uw hele wereldwijde publiek te garanderen.
Conclusie: Performante Grids Ontwerpen met Opzet
CSS Grid is een uitzonderlijk krachtig hulpmiddel, maar de meest geavanceerde functies zijn niet vrij van computationele kosten. Als webprofessionals die ontwikkelen voor een wereldwijd publiek met een breed scala aan apparaten en netwerkomstandigheden, moeten we vanaf het allereerste begin van het ontwikkelingsproces prestatiebewust zijn.
De belangrijkste conclusies zijn duidelijk:
- Layout is een prestatieknelpunt: De 'Layout'-fase van rendering kan duur zijn, vooral met complexe, op beperkingen gebaseerde systemen zoals CSS Grid.
- Dimensioneringsstrategie is belangrijk: Extrinsieke, door de container gedefinieerde dimensionering (`px`, `fr`, `%`) is bijna altijd performanter dan intrinsieke, op inhoud gebaseerde dimensionering (`min-content`, `max-content`, `auto`).
- Meten, niet gokken: Browser performance profilers zijn niet alleen voor debugging. Gebruik ze proactief om uw lay-outkeuzes te analyseren en uw optimalisaties te valideren.
- Optimaliseer voor het meest voorkomende geval: Voor grote verzamelingen items zal een eenvoudige, extrinsieke grid-definitie een betere gebruikerservaring bieden dan een complexe, content-bewuste.
Door performance profiling te integreren in uw reguliere workflow, kunt u geavanceerde, responsieve en robuuste lay-outs bouwen met CSS Grid, met het vertrouwen dat ze niet alleen visueel verbluffend zijn, maar ook ongelooflijk snel en toegankelijk voor gebruikers overal.